using System;
using Qyoto;
using Clandestine.Graphics;
using Clandestine.Graphics.Window;
using System.Linq;

namespace Shlick
{
	public delegate void GLReadyNotification();
	public delegate void MouseMoveEvent(int x, int y);
	public delegate void MouseButtonEvent(int button, bool down);
	public delegate void KeyPressEvent(int k);
	public delegate void KeyReleaseEvent(int k);
	
	public class GLWidget : QGLWidget
	{
		public MapDocument MapDocument { get; private set; }
		public GLWidgetWindowHandler WindowHandler { get; private set; }
		public Graphics Graphics { get; private set; }
		
		public event GLReadyNotification PreRender;
		
		private event GLReadyNotification Ready;
		public event MouseButtonEvent MousePress;
		public event MouseButtonEvent MouseRelease;
		public event MouseMoveEvent MouseMove;
		
		private QBasicTimer timer = new QBasicTimer();
		
		public GLWidget(MapDocument mapDocument, GLReadyNotification ready) : base()
		{		
			this.MapDocument = mapDocument;
			this.Ready += ready;
			this.SetMouseTracking(true);
			
		}
		
		protected override void TimerEvent (QTimerEvent arg1)
		{
			this.Emit.renderQGLWidget();
		}
		
		protected override void MouseMoveEvent(QMouseEvent arg1)
		{
			if (MouseMove != null)
				MouseMove(arg1.X(), arg1.Y());	
		}
		
		protected override void MousePressEvent (QMouseEvent arg1)
		{
			// Todo: doesn't handle anything other than left. gets treated as right
			if (MousePress != null)
				MousePress((arg1.Button() == Qt.MouseButton.LeftButton) ? 0 : 1, true);
		}
		
		protected override void MouseReleaseEvent (QMouseEvent arg1)
		{
			// Todo: doesn't handle anything other than left. gets treated as right
			if (MouseRelease != null)
				MouseRelease((arg1.Button() == Qt.MouseButton.LeftButton) ? 0 : 1, false);
		}
		
		// doc is pretty serious about us doing our shit in here!
		protected override void InitializeGL()
		{
			base.InitializeGL();

			// Setup graphics
			this.MakeCurrent();
			WindowHandler = new GLWidgetWindowHandler(this);
			Graphics = new Graphics((WindowHandler)this.WindowHandler, this.Width(), this.Height());
			
			// Hack render thread so that rendering is done in QT's thread
			Connect(this, Qt.SIGNAL("renderQGLWidget()"), this, Qt.SLOT("updateGL()"));
			Graphics.BlockRendering();
			Graphics.Thread.OverrideRenderFunction = delegate() {
				// invalidate the QT widget
				//this.Emit.renderQGLWidget();
				return true; // so renderthread doesn't actually render.
			};
			Graphics.UnblockRendering();
			
			if (Ready != null)
				Ready();
			
			timer.Start(1, this);
		}
		
		protected override void PaintGL()
		{
			if (PreRender != null)
				PreRender();
			
			this.Graphics.ForceRender();
			
			// Redraw dirty stuff
			this.MapDocument.Map.RedrawDirty();
		}
		
		protected override void ResizeGL (int w, int h)
		{
			this.Graphics.Resize(w, h);
		}
		
		protected new IGLWidgetSignals Emit
		{
			get { return (IGLWidgetSignals) Q_EMIT; }
		}
	}
	
	public interface IGLWidgetSignals : IQGLWidgetSignals
	{
    	[Q_SIGNAL("void renderQGLWidget()")]
    	void renderQGLWidget();
	}
}

